/*
 * The following code is part of https://github.com/jung-kurt/gofpdf
 *
 * Copyright (c) 2019 Arteom Korotkiy (Gmail: arteomkorotkiy)
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package font

import (
	
	
	
	
)

// flags
const symbolWords = 1 << 0
const symbolScale = 1 << 3
const symbolContinue = 1 << 5
const symbolAllScale = 1 << 6
const symbol2x2 = 1 << 7

type utf8FontFile struct {
	fileReader           *fileReader
	tableDescriptions    map[string]*tableDescription
	outTablesData        map[string][]byte
	symbolOffsets        locaOffsets
	charSymbolDictionary map[int]int
}

type tableDescription struct {
	position int
	size     int
}

type fileReader struct {
	readerPosition int64
	array          []byte
}

func ( *fileReader) ( int) []byte {
	 := .array[.readerPosition : .readerPosition+int64()]
	.readerPosition += int64()
	return 
}

func newUTF8Font( *fileReader) *utf8FontFile {
	 := utf8FontFile{
		fileReader: ,
	}
	return &
}

func ( *utf8FontFile) () {

	 := .readUint16()
	_ = .readUint16()
	_ = .readUint16()
	_ = .readUint16()
	.tableDescriptions = make(map[string]*tableDescription)

	for  := 0;  < ; ++ {
		 := string(.fileReader.Read(4))
		.skip(4) // Skip the input table checksum; output checksums are recalculated.
		.tableDescriptions[] = &tableDescription{
			position: .readUint32(),
			size:     .readUint32(),
		}
	}
}

func ( *utf8FontFile) () int {
	 := .fileReader.Read(2)
	return (int([0]) << 8) + int([1])
}

func ( *utf8FontFile) () int {
	 := .fileReader.Read(4)
	return (int([0]) * 16777216) + (int([1]) << 16) + (int([2]) << 8) + int([3]) // 	16777216  = 1<<24
}

func ( *utf8FontFile) (,  []int) []int {
	 := make([]int, 2)
	if [1] > [1] {
		[1] += 1 << 16
		[0]++
	}
	[1] = [1] - [1]
	if [0] > [0] {
		[0] += 1 << 16
	}
	[0] = [0] - [0]
	[0] = [0] & 0xFFFF
	return 
}

func ( *utf8FontFile) ( []byte) []int {
	if (len() % 4) != 0 {
		for  := 0; (len() % 4) != 0; ++ {
			 = append(, 0)
		}
	}
	 := []int{0x0000, 0x0000}
	for  := 0;  < len();  += 4 {
		[0] += (int([]) << 8) + int([+1])
		[1] += (int([+2]) << 8) + int([+3])
		[0] += [1] >> 16
		[1] = [1] & 0xFFFF
		[0] = [0] & 0xFFFF
	}
	return 
}

func ( *utf8FontFile) ( int) {
	.fileReader.readerPosition = int64()
}

func ( *utf8FontFile) ( int) {
	.fileReader.readerPosition += int64()
}

// SeekTable position
func ( *utf8FontFile) ( string) int {
	.seek(.tableDescriptions[].position)
	return int(.fileReader.readerPosition)
}

func ( *utf8FontFile) () int16 {
	 := .fileReader.Read(2)
	 := (int16([0]) << 8) + int16([1])
	if (int() & (1 << 15)) == 0 {
		 = int16(int() - (1 << 16))
	}
	return 
}

func ( *utf8FontFile) ( int) int {
	.seek()
	 := .fileReader.Read(2)
	return (int([0]) << 8) + int([1])
}

func ( *utf8FontFile) ( []byte,  int,  []byte) []byte {
	 = append([]byte{}, ...)
	return append(append([:], ...), [+len():]...)
}

func ( *utf8FontFile) ( []byte,  int,  int) []byte {
	 := make([]byte, 2)
	binary.BigEndian.PutUint16(, uint16())
	return .splice(, , )
}

func ( *utf8FontFile) (,  int) []byte {
	.seek()
	if  < 1 {
		return make([]byte, 0)
	}
	 := .fileReader.Read()
	return 
}

func ( *utf8FontFile) ( string) []byte {
	 := .tableDescriptions[]
	if  == nil {
		return nil
	}
	if .size == 0 {
		return nil
	}
	.seek(.position)
	 := .fileReader.Read(.size)
	return 
}

func ( *utf8FontFile) ( string,  []byte) {
	if  == nil {
		return
	}
	if  == "head" {
		 = .splice(, 8, []byte{0, 0, 0, 0})
	}
	.outTablesData[] = 
}

func ( *utf8FontFile) () map[int]int {
	 := .SeekTable("cmap")
	.skip(2)
	 := .readUint16()
	 := 0
	for  := 0;  < ; ++ {
		 := .readUint16()
		 := .readUint16()
		 := .readUint32()
		 := .fileReader.readerPosition
		if ( == 3 &&  == 1) ||  == 0 {
			 := .getUint16( + )
			if  == 4 {
				 =  + 
				break
			}
		}
		.seek(int())
	}

	if  == 0 {
		fmt.Printf("Font does not have cmap for Unicode\n")
		return nil
	}

	 := make(map[int]int)
	.generateCharSymbolDictionary(, )

	return 
}

func ( *utf8FontFile) ( map[int]int) (map[int]int, map[int]int, map[int]int, []int) {
	 := map[int]int{0: 0}
	 := make(map[int]int)
	for ,  := range  {
		if ,  := .charSymbolDictionary[];  {
			[.charSymbolDictionary[]] = 
			[] = .charSymbolDictionary[]

		}
	}

	 := .tableDescriptions["glyf"].position

	 := make(map[int]int)
	 := keySortInt()

	 := 0
	for ,  := range  {
		[] = 
		++
	}
	 := keySortInt()
	 := make(map[int]int)
	for ,  := range  {
		[] = [[]]
	}

	for ,  := range  {
		_, , ,  = .getSymbols(, &, , , )
	}

	return , , , 
}

func ( *utf8FontFile) ( map[int]int,  int) []byte {
	 := keySortInt()
	 := 0
	 := make(map[int][]int)
	 := -2
	 := -1
	for ,  := range  {
		if  == (+1) && [] == (+1) {
			if ,  := []; ! ||  == nil {
				[] = make([]int, 0)
			}
			[] = append([], [])
		} else {
			 = 
			[] = make([]int, 0)
			[] = append([], [])
		}
		 = 
		 = []
	}
	 := keySortArrayRangeMap()
	 := len() + 1

	 := 1
	 := 0
	for *2 <=  {
		 =  * 2
		 =  + 1
	}
	 =  * 2
	 := *2 - 

	 := []int{0, 1, 3, 1, 0, 12, 4}

	 := []int{ * 2, , , }
	for ,  := range  {
		 :=  + (len([]) - 1)
		 = append(, )
	}
	 = append(, 0xFFFF)
	 = append(, 0)

	 = append(, ...)
	 = append(, 0xFFFF)
	for ,  := range  {
		 := -( - [][0])
		 = append(, )
	}
	 = append(, 1)
	for range  {
		 = append(, 0)

	}
	 = append(, 0)
	for ,  := range  {
		 = append(, []...)
	}
	 = append(, 0)

	// Calculating cmap length based off of fpdf https://github.com/Setasign/FPDF/blob/f4104a04c9a3f95c4c26a0a0531abebcc980987a/makefont/ttfparser.php#L476
	// https://learn.microsoft.com/en-us/typography/opentype/spec/cmap#format-4-segment-mapping-to-delta-values
	// The 3 extra bytes are for encodingID, offset, format, which are also part of the cmap
	 := (3 + len()) * 2
	 = append(, , 0)
	 = append(, ...)

	 := make([]byte, 0)
	for ,  := range  {
		 = append(, packUint16()...)
	}

	return 
}

// GenerateCutFont fill utf8FontFile from .utf file, only with runes from usedRunes
func ( *utf8FontFile) ( map[int]int) []byte {
	.fileReader.readerPosition = 0
	.outTablesData = make(map[string][]byte)
	.skip(4)
	.generateTableDescriptions()

	.SeekTable("head")
	.skip(50)
	 := .readUint16()

	.SeekTable("hhea")
	.skip(34)
	 := .readUint16()
	 := 

	.SeekTable("maxp")
	.skip(4)
	 := .readUint16()

	.charSymbolDictionary = .generateCMAP()
	if .charSymbolDictionary == nil {
		return nil
	}

	.parseLOCATable(, )

	, , ,  := .parseSymbols()

	 = len()
	 = 

	.setOutTable("name", .getTableData("name"))
	.setOutTable("cvt ", .getTableData("cvt "))
	.setOutTable("fpgm", .getTableData("fpgm"))
	.setOutTable("prep", .getTableData("prep"))
	.setOutTable("gasp", .getTableData("gasp"))

	 := .getTableData("post")
	 = append(append([]byte{0x00, 0x03, 0x00, 0x00}, [4:16]...), []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}...)
	.setOutTable("post", )

	delete(, 0)

	.setOutTable("cmap", .generateCMAPTable(, ))

	 := .getTableData("glyf")

	 := make([]int, 0)
	 := make([]byte, 0)
	 := 0
	 := make([]byte, 0)

	for ,  := range  {
		 := .getMetrics(, )
		 = append(, ...)

		 = append(, )
		 := .symbolOffsets.at()
		 := .symbolOffsets.at(+1) - 
		 := [ : +]
		var  int
		if  > 0 {
			 = unpackUint16([0:2])
		}

		if  > 2 && (&(1<<15)) != 0 {
			 := 10
			 := symbolContinue
			for ( & symbolContinue) != 0 {
				 = unpackUint16([ : +2])
				 = 
				 = unpackUint16([+2 : +4])
				 := 
				 = .insertUint16(, +2, [])
				 += 4
				if ( & symbolWords) != 0 {
					 += 4
				} else {
					 += 2
				}
				if ( & symbolScale) != 0 {
					 += 2
				} else if ( & symbolAllScale) != 0 {
					 += 4
				} else if ( & symbol2x2) != 0 {
					 += 8
				}
			}
		}

		 = append(, ...)
		 += 
		if %4 != 0 {
			 := 4 - ( % 4)
			 = append(, make([]byte, )...)
			 += 
		}
	}

	 = append(, )
	.setOutTable("glyf", )

	.setOutTable("hmtx", )

	 := make([]byte, 0)
	if (( + 1) >> 1) > 0xFFFF {
		 = 1
		for ,  := range  {
			 = append(, packUint32()...)
		}
	} else {
		 = 0
		for ,  := range  {
			 = append(, packUint16(/2)...)
		}
	}
	.setOutTable("loca", )

	 := .getTableData("head")
	 = .insertUint16(, 50, )
	.setOutTable("head", )

	 := .getTableData("hhea")
	 = .insertUint16(, 34, )
	.setOutTable("hhea", )

	 := .getTableData("maxp")
	 = .insertUint16(, 4, )
	.setOutTable("maxp", )

	 := .getTableData("OS/2")
	.setOutTable("OS/2", )

	return .assembleTables()
}

func ( *utf8FontFile) ( int,  *int,  map[int]int,  map[int]int,  []int) (*int, map[int]int, map[int]int, []int) {
	 := .symbolOffsets.at()
	 := .symbolOffsets.at(+1) - 
	if  == 0 {
		return , , , 
	}
	.seek(* + )

	 := .readInt16()

	if  < 0 {
		.skip(8)
		 := symbolContinue
		for &symbolContinue != 0 {
			 = .readUint16()
			 := .readUint16()
			if ,  := []; ! {
				[] = len()
				[] = 1
				 = append(, )
			}
			 := .fileReader.readerPosition
			_, _, _,  = .(, , , , )
			.seek(int())
			if &symbolWords != 0 {
				.skip(4)
			} else {
				.skip(2)
			}
			if &symbolScale != 0 {
				.skip(2)
			} else if &symbolAllScale != 0 {
				.skip(4)
			} else if &symbol2x2 != 0 {
				.skip(8)
			}
		}
	}
	return , , , 
}

func ( *utf8FontFile) (,  int) []byte {
	 := .SeekTable("hmtx")
	var  []byte
	if  <  {
		.seek( + ( * 4))
		 = .fileReader.Read(4)
	} else {
		.seek( + (( - 1) * 4))
		 = .fileReader.Read(2)
		.seek( + ( * 2) + ( * 2))
		 = append(, .fileReader.Read(2)...)
	}
	return 
}

// locaOffsets keeps the original table snapshot while decoding only the glyphs
// selected for the subset. A font can have far more glyphs than a diagram uses.
type locaOffsets struct {
	data  []byte
	width int
}

func ( locaOffsets) ( int) int {
	 := 0
	if .width != 0 {
		 = len(.data) / .width
	}
	// Preserve the decoded array's glyph-index bounds check before computing a
	// byte offset, including invalid glyph IDs in malformed composite glyphs.
	_ = .data[:][]
	 := .data[*.width:]
	if .width == 2 {
		return int(binary.BigEndian.Uint16()) * 2
	}
	return int(binary.BigEndian.Uint32())
}

func ( *utf8FontFile) (,  int) {
	 := .SeekTable("loca")
	.symbolOffsets = locaOffsets{}
	 := 0
	switch  {
	case 0:
		 = 2
	case 1:
		 = 4
	default:
		fmt.Printf("Unknown loca table format %d\n", )
		return
	}
	// Read the full table now, retaining the original truncation check and reader
	// position. Copy the bytes because later metric extraction can mutate the
	// input; even overlapping custom-font tables must retain the old snapshot.
	 := .getRange(, (+1)*)
	.symbolOffsets = locaOffsets{data: bytes.Clone(), width: }
}

func ( *utf8FontFile) ( int,  map[int]int) {
	.seek( + 2)
	 := .readUint16()
	 :=  + 
	.skip(2)

	 := .readUint16() / 2
	.skip(6)
	 := make([]int, 0)
	for  := 0;  < ; ++ {
		 = append(, .readUint16())
	}
	.skip(2)
	 := make([]int, 0)
	for  := 0;  < ; ++ {
		 = append(, .readUint16())
	}
	 := make([]int, 0)
	for  := 0;  < ; ++ {
		 = append(, int(.readInt16()))
	}
	 := .fileReader.readerPosition
	 := make([]int, 0)
	for  := 0;  < ; ++ {
		 = append(, .readUint16())
	}
	var  int
	for  := 0;  < ; ++ {
		 := [] + 1
		for  := [];  < ; ++ {
			if [] == 0 {
				 = ( + []) & 0xFFFF
			} else {
				 := (-[])*2 + []
				 = int() + 2* + 
				if  >=  {
					 = 0
				} else {
					 = .getUint16()
					if  != 0 {
						 = ( + []) & 0xFFFF
					}
				}
			}
			[] = 
		}
	}
}

func ( *utf8FontFile) () []byte {
	 := make([]byte, 0)
	 := len(.outTablesData)
	 := 1
	 := 0
	for *2 <=  {
		 =  * 2
		 =  + 1
	}
	 =  * 16
	 := *16 - 

	 = append(, packHeader(0x00010000, , , , )...)

	 := .outTablesData
	 := keySortStrings()

	 := 12 + *16
	 := 0

	for ,  := range  {
		if  == "head" {
			 = 
		}
		 = append(, []byte()...)
		 := .generateChecksum([])
		 = append(, pack2Uint16([0], [1])...)
		 = append(, pack2Uint32(, len([]))...)
		 := (len([]) + 3) &^ 3
		 =  + 
	}

	for ,  := range  {
		 := append([]byte{}, []...)
		 = append(, []byte{0, 0, 0}...)
		 = append(, [:(len()&^3)]...)
	}

	 := .generateChecksum([]byte())
	 = .calcInt32([]int{0xB1B0, 0xAFBA}, )
	 = .splice(, ( + 8), pack2Uint16([0], [1]))
	return 
}

func unpackUint16( []byte) int {
	return int(binary.BigEndian.Uint16())
}

func packHeader( uint32, , , ,  int) []byte {
	 := make([]byte, 0)
	 := make([]byte, 4)
	binary.BigEndian.PutUint32(, )
	 = append(, ...)
	 := make([]byte, 2)
	binary.BigEndian.PutUint16(, uint16())
	 = append(, ...)
	binary.BigEndian.PutUint16(, uint16())
	 = append(, ...)
	binary.BigEndian.PutUint16(, uint16())
	 = append(, ...)
	binary.BigEndian.PutUint16(, uint16())
	 = append(, ...)
	return 
}

func pack2Uint16(,  int) []byte {
	 := make([]byte, 0)
	 := make([]byte, 2)
	binary.BigEndian.PutUint16(, uint16())
	 = append(, ...)
	binary.BigEndian.PutUint16(, uint16())
	 = append(, ...)
	return 
}

func pack2Uint32(,  int) []byte {
	 := make([]byte, 0)
	 := make([]byte, 4)
	binary.BigEndian.PutUint32(, uint32())
	 = append(, ...)
	binary.BigEndian.PutUint32(, uint32())
	 = append(, ...)
	return 
}

func packUint32( int) []byte {
	 := make([]byte, 4)
	binary.BigEndian.PutUint32(, uint32())
	return 
}

func packUint16( int) []byte {
	 := make([]byte, 2)
	binary.BigEndian.PutUint16(, uint16())
	return 
}

func keySortStrings( map[string][]byte) []string {
	 := make([]string, len())
	 := 0
	for  := range  {
		[] = 
		++
	}
	sort.Strings()
	return 
}

func keySortInt( map[int]int) []int {
	 := make([]int, len())
	 := 0
	for  := range  {
		[] = 
		++
	}
	sort.Ints()
	return 
}

func keySortArrayRangeMap( map[int][]int) []int {
	 := make([]int, len())
	 := 0
	for  := range  {
		[] = 
		++
	}
	sort.Ints()
	return 
}

// UTF8CutFont is a utility function that generates a TrueType font composed
// only of the runes included in cutset. The rune glyphs are copied from This
// function is demonstrated in ExampleUTF8CutFont().
func ( []byte,  string) ( []byte) {
	 := newUTF8Font(&fileReader{readerPosition: 0, array: })
	 := map[int]int{}
	for ,  := range  {
		[] = int()
	}
	 = .GenerateCutFont()
	return
}